#ifndef _ESC_THREAD_H_
#define _ESC_THREAD_H_

/*
 * Essential-C - Essential C Libraries for Developers
 * Copyright (c) 2004-2008 Tom Bradford <tom@tbradford.org>
 *
 * Permission is hereby granted, free of charge, to any person obtaining a 
 * copy of this software and associated documentation files (the "Software"),
 * to deal in the Software without restriction, including without limitation
 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
 * and/or sell copies of the Software, and to permit persons to whom the
 * Software is furnished to do so, subject to the following conditions:
 * 
 * The above copyright notice and this permission notice shall be included
 * in all copies or substantial portions of the Software.
 * 
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 
 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 
 * DEALINGS IN THE SOFTWARE.
 */

/**
 * Wraps and abstracts basic threading constructs such as threads 
 * and mutexes.  You'll notice that only the base minimum 
 * functionality is exposed.  This is for purposes of both ease
 * of use and portability.
 */

#include <stdbool.h>
#include <stdlib.h>

#include "esc_mem.h"

#ifdef __cplusplus
extern "C" {
#endif // __cplusplus


/** Incomplete type for Thread instances */
typedef struct esc_thread_t esc_thread_t;

/** Incomplete type for Mutex instances */
typedef struct esc_mutex_t esc_mutex_t;

/** Function type for Thread execution and cleanup */
typedef bool esc_thread_function_t(esc_thread_t* thread, void* context);
                                             
/** Create an Thread instance */
esc_thread_t* esc_thread_new(esc_mem_t* mem);

/** Initializes the most common attributes of a Thread instance */
esc_thread_t* esc_thread_init(esc_thread_t* thread,
                              esc_thread_function_t* runnableFunction,
                              esc_thread_function_t* cleanupFunction,
                              void* context);

/** Sets the Runnable function for the Thread instance */
void esc_thread_setRunnableFunction(esc_thread_t* thread, 
                                    esc_thread_function_t* runnableFunction);

/** Returns the Runnable function for the Thread instance */
esc_thread_function_t* esc_thread_getRunnableFunction(esc_thread_t* thread);

/** Sets the Cleanup function for the Thread instance */
void esc_thread_setCleanupFunction(esc_thread_t* thread, 
                                   esc_thread_function_t* cleanupFunction);

/** Returns the Cleanup function for the Thread instance */
esc_thread_function_t* esc_thread_getCleanupFunction(esc_thread_t* thread);

/** Sets the Context for the Thread instance */
void esc_thread_setContext(esc_thread_t* thread, void* context);

/** Returns the Context for the Thread instance */
void* esc_thread_getContext(esc_thread_t* thread);

/** Starts The Thread instance's Runnable function */
bool esc_thread_start(esc_thread_t* thread);

/** Stops the Thread instance's execution */
bool esc_thread_stop(esc_thread_t* thread);

/** Joins a Thread instance's execution (waits for Thread to end) */
bool esc_thread_join(esc_thread_t* thread);

/** Returns whether or not the Thread insance is executing */
bool esc_thread_isRunning(esc_thread_t* thread);

/** Create a Mutex instance */
esc_mutex_t* esc_mutex_new(esc_mem_t* mem);

/** Instructs the current Thread to wait until the Mutex is notified */
void esc_mutex_wait(esc_mutex_t* mutex);

/** Notifies a Thread that the Mutex instance is able to proceed */
void esc_mutex_notify(esc_mutex_t* mutex);

/** Notifies all Threads that the Mutex instance is able to proceed */
void esc_mutex_notifyAll(esc_mutex_t* mutex);

/** Locks the Mutex instance.  Blocks if locked already */
bool esc_mutex_lock(esc_mutex_t* mutex);

/** Attempts a Lock on the Mutex instance.  Fails if locked already */
bool esc_mutex_tryLock(esc_mutex_t* mutex);

/** Unlocks the Mutex instance */
bool esc_mutex_unlock(esc_mutex_t* mutex);


#ifdef __cplusplus
}
#endif // __cplusplus

#endif // _ESC_THREAD_H_
